Crate error_stack_derive
source · [−]Expand description
The heart of this crate is ErrorStack
,
its a derive macro to make generating enums and structs compatible
with error_stack.
Even though the sole purpose is provind a better DX with error_stack
this derive macro can actually be used with any other error system
since the crate itself doesn’t depend on error_stack
all it does
is makes std::error::Error
and std::fmt::Display
implementations
easy.
Usage with and without error_stack
With
Note: As of right-now
no-std
is not supported
With error_stack
you get the Report
and their fancy attachments,
context, frames, etc. features, which to say the least are
pretty cool and helpful for error handling & debugging.
use error_stack::{IntoReport, Result, ResultExt};
use error_stack_derive::ErrorStack;
#[derive(ErrorStack, Debug)]
#[error_message("An exception occured in foo")]
struct FooError;
fn main() -> Result<(), FooError> {
let contents = std::fs::read_to_string("foo.txt")
.report()
.change_context(FooError)
.attach_printable("Unable to read foo.txt file")?;
println!("{contents}");
Ok(())
}
Without
Ofcourse this crate doesn’t enforce the usage of error_stack
infact you can use it with any other error handling crate,
just like this
use error_stack_derive::ErrorStack;
#[derive(ErrorStack, Debug)]
#[error_message(&format!("An exception occured with foo: {}", self.0))]
struct FooError(String);
fn main() -> Result<(), FooError> {
let contents = std::fs::read_to_string("foo.txt").map_err(|e| FooError(e.to_string()))?;
println!("{contents}");
Ok(())
}
Looking into the expansion
This crate, specifically the derive macro, does 2 things,
one, implements std::error::Error
two, implements std::fmt::Display
you can derive a struct or an enum, the trait impl are pretty
simple
For a struct:
// #[derive(error_stack_derive::ErrorStack, Debug)]
// #[error_message("An exception occured in foo")]
// struct FooError;
#[derive(Debug)]
struct FooError;
impl std::fmt::Display for FooError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.write_str("An exception occured in foo")
}
}
impl std::error::Error for FooError {}
For an enum:
// #[derive(error_stack_derive::ErrorStack, Debug)]
// enum FooErrors {
// #[error_message("An exception in bar")]
// BarError,
// #[error_message(&format!("Error in baz ({unnamed0})"))]
// BazError(String),
// #[error_message(&format!("Error in qux ({start}, {end})"))]
// QuxError {
// start: u64,
// end: u64,
// }
// };
#[derive(Debug)]
enum FooErrors {
BarError,
BazError(String),
QuxError {
start: u64,
end: u64,
}
};
impl std::fmt::Display for FooErrors {
fn fmt(&self, _____fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::BarError => _____fmt.write_str(&format!("[{name}] An error occured; {:?}", name = "FooErrors", self)),
Self::BazError(unnamed0) => _____fmt.write_str(&format!("Error in baz ({unnamed0})")),
Self::QuxError { start, end } => _____fmt.write_str(&format!("Error in qux ({start}, {end})")),
}
}
}
impl std::error::Error for FooErrors {}
As you can see its a pretty simple macro but definitely helps when
you have a large code base and error handling definitely becomes dreadful.
Read up the doc comments of ErrorStack
for more information.
Derive Macros
A derive-macro to easily create enums and structs compatible with error_stack. You can use a struct or an enum with it